﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
using CommunityServerRest.HtmlEncoding;

namespace CommunityServerRest {
	public class BlogService {

		string blogServiceUrl;
		string header;

		ServiceCredentials serviceCredentials;
		public ServiceCredentials Credentials {
			get {
				return serviceCredentials;
			}
			set {
				serviceCredentials = value;
				if (value != null) {
					blogServiceUrl = string.Concat(serviceCredentials.ServiceUrl, "/api/blogs.ashx");
					header = GenerateLoginHeader();
				}
			}
		}
		public BlogService() {
		}
		public BlogService(ServiceCredentials credentials) {
			Credentials = credentials;
		}
		public BlogService(string serviceUrl, string username, string apiKey) {
			Credentials=new ServiceCredentials(serviceUrl, username, apiKey);
		}

		private void SetCredentials(string serviceUrl, string username, string apiKey) {
		}

		private string GenerateLoginHeader() {
			string cabecera = "Rest-User-Token: ";
			string token = string.Concat(serviceCredentials.ApiKey, ":", serviceCredentials.Username);
			byte[] tokenBytes;

			ASCIIEncoding enc = new ASCIIEncoding();
			tokenBytes = enc.GetBytes(token);

			string base64 = Convert.ToBase64String(tokenBytes);

			return cabecera + base64;
		}

		public Blog GetBlog(int blogId) {
			string uri = string.Concat(blogServiceUrl, "/blogs/", blogId);
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
			request.Headers.Add(header);

			Stream stream = request.GetResponse().GetResponseStream();
			Blog blog = Blog.Deserialize(stream);
			stream.Close();
			return blog;
		}

		public BlogList Blogs() {
			string uri=string.Concat(blogServiceUrl, "/Blogs/");
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
			request.Headers.Add(header);

			Stream stream = request.GetResponse().GetResponseStream();
			BlogList blogList = BlogList.Deserialize(stream);
			stream.Close();
			return blogList;
		}

		public BlogPostList BlogPosts(int id) {
			string uri = string.Concat(blogServiceUrl, "/Blogs/" + id.ToString(), "/posts");
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
			request.Headers.Add(header);
			BlogPostList postList = BlogPostList.Deserialize(request.GetResponse().GetResponseStream());
			return postList;
		}

		public BlogPostList GetRecentPosts(int max) {
			return GetPostsQuery( string.Concat("PageSize=", max, ";SortBy=Date;SortOrder=Descending") );
		}
		public BlogPostList GetPostsQuery(string query) {
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Concat(blogServiceUrl, "/Posts/" + query));
			request.Headers.Add(header);
			request.Timeout = 10000;
			request.ReadWriteTimeout = 10000;
			WebResponse response = request.GetResponse();
			Stream stream = response.GetResponseStream();

			CommunityServerRest.BlogPostList postList = CommunityServerRest.BlogPostList.Deserialize(stream);
			stream.Close();
			response.Close();
			return postList;
		}

		public BlogPost GetPost(int id) {
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Concat(blogServiceUrl, "/Posts/" + id.ToString()));
			request.Headers.Add(header);
			request.Timeout = 10000;
			request.ReadWriteTimeout = 10000;

			WebResponse response = request.GetResponse();
			Stream stream = response.GetResponseStream();

			CommunityServerRest.BlogPost post = CommunityServerRest.BlogPost.Deserialize(stream);
			stream.Close();

			HtmlDecode(post);
			return post;
		}

		private void HtmlDecode(BlogPost post) {
			post.Body = HttpUtility.HtmlDecode(post.Body);
			post.Title = HttpUtility.HtmlDecode(post.Title);

			if (post.Keywords.Keyword != null) {
				for (int t = 0; t < post.Keywords.Keyword.Count; t++) {
					post.Keywords.Keyword[t] = HttpUtility.HtmlDecode(post.Keywords.Keyword[t]);
				}
			}
		}

		public BlogPost CreatePost(BlogPost post, int blogId) {
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Concat(blogServiceUrl, "/blogs/", blogId, "/posts/"));
			request.Method = "POST";
			request.ContentType = "application/xml";
			request.Headers.Add(header);
			request.AllowWriteStreamBuffering = true;		//Sin esta línea, muere

			Stream stream = request.GetRequestStream();
			post.Serialize(stream);
			stream.Close();

			// Parte de procesamiento de la respuesta
			WebResponse response = request.GetResponse();
			Stream responseStream = response.GetResponseStream();
			BlogPost returnedPost = BlogPost.Deserialize(responseStream);

			return returnedPost;
		}

		public BlogPost UpdatePost(BlogPost post) {
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Concat(blogServiceUrl, "/posts/", post.Id));
			
			request.Method = "POST";
			request.Headers.Add("Verb: PUT");

			request.ContentType = "application/xml";
			request.Headers.Add(header);
			request.AllowWriteStreamBuffering = true;		//Sin esta línea, muere

			Stream stream = request.GetRequestStream();
			post.Serialize(stream);
			stream.Close();

			// Parte de procesamiento de la respuesta
			WebResponse response = request.GetResponse();
			Stream responseStream = response.GetResponseStream();
			BlogPost returnedPost = BlogPost.Deserialize(responseStream);

			return returnedPost;
		}
	
		public void CreateAttachment(int postId, string path) {
			CreateAttachment(postId, Path.GetFileName(path), new FileStream(path, FileMode.Open));
		}




		public Attachment GetAttachment(int postId) {
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Concat(blogServiceUrl, "/posts/", postId, "/attachment"));
			request.Headers.Add(header); // Adds the required Rest-User-Token header
			//request.SendChunked = false;
			
			request.Timeout = 10000;
			request.ReadWriteTimeout = 10000;

			WebResponse response = request.GetResponse();

			Attachment a;

			a = ReadAttachmentFromResponse(response);


			return a;
		}

		private Attachment ReadAttachmentFromResponse(WebResponse response) {
			byte[] contents;

			long length = response.ContentLength;

			Stream stream = response.GetResponseStream();
			contents = new byte[length];

			int totalBytes = 0;
			while (totalBytes < length) {
				totalBytes += stream.Read(contents, totalBytes, (int)(length - totalBytes));
			}

			stream.Close();

			return new Attachment(GetAttachmentFilename(response), contents);
		}


		private string GetAttachmentFilename(WebResponse response) {
			try {
				string token = "filename=";
				string header = response.Headers["Content-Disposition"];
				int pos = header.IndexOf(token) + token.Length;
				return header.Substring(pos);
			} catch {
				Uri uri = response.ResponseUri;
				int last = uri.Segments.Length;
				string filename = uri.Segments[last-1];
				return filename;
			}
		}

		private void CreateAttachment(int postId, string postName, Stream sourceStream) {
			// Creates the web request to the required URI
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Concat(blogServiceUrl, "/posts/", postId, "/attachment"));
			// We need POST
			request.Method = "POST";
			request.AllowWriteStreamBuffering = true;

			request.Headers.Add(header); // Adds the required Rest-User-Token header
			string boundary = Guid.NewGuid().ToString();
			request.ContentType = "multipart/form-data; boundary=" + boundary;


			Stream stream = request.GetRequestStream();

			WriteAttachmentToStream(sourceStream, postName, boundary, stream);

			stream.Close();
			request.GetResponse();
		}

		private void WriteAttachmentToStream(Stream inputStream, string attachmentName, string boundary, Stream outputStream) {
			StreamWriter writer = new StreamWriter(outputStream);
			writer.WriteLine("--" + boundary);
			writer.WriteLine("Content-Disposition: form-data; name=\"file\"; filename=\"" + attachmentName + "\"");
			writer.WriteLine("Content-Type: image/pjpeg");
			writer.WriteLine();
			writer.Flush();

			// Stream dump to outputStream
			byte[] data = new byte[inputStream.Length];
			inputStream.Read(data, 0, (int)inputStream.Length);
			outputStream.Write(data, 0, (int)inputStream.Length);
			outputStream.Flush();

			writer.WriteLine("\n--" + boundary + "--");
			writer.Flush();
		}

		/*
		private void WriteRawFile(string path, string name, string boundary, Stream stream) {
			StreamWriter writer = new StreamWriter(stream);
			writer.WriteLine("--" + boundary);
			writer.WriteLine("Content-Disposition: form-data; name=\"file\"; filename=\""+ name + "\"");
			writer.WriteLine("Content-Type: image/pjpeg");
			writer.WriteLine();
			writer.Flush();

			FileStream file = new FileStream(path, FileMode.Open);
			byte[] data = new byte[file.Length];
			file.Read(data, 0, (int) file.Length);

			stream.Write(data, 0, (int) file.Length);

			writer.WriteLine("\n--" + boundary + "--");
			writer.Flush();
		}
		*/

		public void Delete(int postId) {

			HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(string.Concat(blogServiceUrl, "/posts/" + postId.ToString()));
			request.Method = "POST";
			request.Headers.Add(header);
			request.Headers.Add("verb: DELETE");
			request.ContentLength = 0;
			request.KeepAlive = false;

			request.GetRequestStream().Close();		//Imprescindible si quiero cerrar la conexión, ya que no pido nada

			WebResponse response = request.GetResponse();
			StreamReader reader = new StreamReader(response.GetResponseStream());
			string s=reader.ReadToEnd();

			response.Close();
		}

		public void DeleteAttachment(int postId) {

			//URI Template: DELETE /api/blogs.ashx/[blogs/{BlogId}/]posts/{PostId}/attachment

			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Concat(blogServiceUrl, "/posts/", postId, "/attachment"));
			request.Method = "POST";
			request.Headers.Add(header);
			request.Headers.Add("verb: DELETE");
			request.ContentLength = 0;
			request.KeepAlive = false;

			request.GetRequestStream().Close();

			request.Timeout = 20000;
			request.ReadWriteTimeout = 20000;

			WebResponse response = request.GetResponse();
			response.Close();
		}

		private void UpdateAttachment(int postId, string postName, Stream sourceStream) {

			// URI template: /api/blogs.ashx/[blogs/{BlogId}/]posts/{PostId}/attachment

			// Creates the web request to the required URI
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Concat(blogServiceUrl, "/posts/", postId, "/attachment"));
			// We need "POST" and the verb "PUT"
			request.Method = "POST";
			request.Headers.Add("Verb: PUT");
			request.AllowWriteStreamBuffering = true;

			request.Headers.Add(header); // Adds the required Rest-User-Token header
			string boundary = Guid.NewGuid().ToString();
			request.ContentType = "multipart/form-data; boundary=" + boundary;


			Stream stream = request.GetRequestStream();

			WriteAttachmentToStream(sourceStream, postName, boundary, stream);

			stream.Close();
			request.GetResponse();
		}

		public void CreateAttachment(Attachment attachment, int postId) {
			using (MemoryStream ms=new MemoryStream(attachment.Contents)) {
				CreateAttachment(postId, attachment.Filename, ms);
				ms.Close();
			}
		}

		public void UpdateAttachment(Attachment attachment, int postId) {
			using (MemoryStream ms = new MemoryStream(attachment.Contents)) {
				UpdateAttachment(postId, attachment.Filename, ms);
				ms.Close();
			}
		}

		public void UpdateAttachment(int postId) {
			// URI Template: PUT /api/blogs.ashx/[blogs/{BlogId}/]posts/{PostId}/attachment
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Concat(blogServiceUrl, "/posts/", postId, "/attachment"));
			request.Method = "POST";
			request.Headers.Add(header);
			request.Headers.Add("Verb: DELETE");
			request.ContentLength = 0;
			request.Timeout = 20000;
			request.ReadWriteTimeout = 20000;

			WebResponse response = request.GetResponse();
		}

		public object Keywords() {
			throw new NotImplementedException();
		}
	}
}
